//////Process Table header file/////////////////////
#ifndef PROCESS_H
#define PROCESS_H

#ifdef USER_PROGRAM

#include "addrspace.h"
#include "syscall.h"
//#include "../threads/system.h"
#include "../threads/synch.h"

#define NUMBER_OF_PROCESSES 4
#define NUMBER_OF_THREADS_PER_PROCESS 60

using namespace std;

class ProcessEntry
{
public:
	ProcessEntry();
	~ProcessEntry();
	SpaceId Get_SpaceId() { return id; } //To be implemented later
	AddrSpace* Get_AddressSpace() { return parentAddressSpace; } //Return address space associated with this process
	int Get_Top_Of_Stack() { return topOfProcessStack; } //Return virtual page number of the top of the stack associated with this process
	void Set_Top_Of_Stack(int top) { topOfProcessStack = top; } //Set virtual page number of the top of the stack associated with this process
	void Associate_Id(SpaceId newId) { id = newId; } //Set ID for this process; not used for current project
	void Associate_AddressSpace(AddrSpace* newSpace) { parentAddressSpace = newSpace; } //Associate an address space with this process entry
	void CleanUp(); //Clean up an entry in the array

private:
	int topOfProcessStack; //virtual page number of top of process stack
	AddrSpace* parentAddressSpace; //address space associated with this process
	SpaceId id; // To be implemented in later projects; meant to identify processes with unique integer id
};

class ThreadEntry
{
public:
	ThreadEntry();
	~ThreadEntry();
	void Associate_Thread(Thread* newThread) { thread = newThread; } // Associate a thread with this entry
	void Associate_Stack_Location(int location) { topOfStack = location; } // Associate a virtual page number for the top of the stack originally allocated to the thread associated with this entry
	Thread* Get_Thread() { return thread; } //Return the thread associated with this entry
	int Get_Virtual_Stack_Location() { return topOfStack; } //Return virtual page number of the top of the stack allocated for this thread
	void CleanUp() { thread = NULL; } //Clean up thread entry

private:
	int topOfStack;
	Thread* thread;
};

class ProcessTable
{
public:
	ProcessTable();
	~ProcessTable();
	void Add_Thread_Entry(Thread*, AddrSpace*, int); //Add a thread entry to the process table
	void Add_Process_Entry(AddrSpace*); //Add a process entry to the process table
	int Get_Num_Threads(); //Get the total number of active threads in the process table
	int Get_Num_Proccesses() { return numberOfActiveProcesses; } //Get the total number of active processes in the process table
	bool Is_Last_Thread_In_Process(AddrSpace*); //Check if process associated with specified address space has any threads active
	int Get_Top_Of_Stack(Thread*);	//Get virtual page number for stack associated with specified thread
	int Get_Top_Of_Process_Stack(AddrSpace*); //Get virtual page number for stack associated with specified process
	void Remove_Thread_Entry(Thread*); //Remove a thread entry
	void Remove_Process_Entry(AddrSpace*); //Remove a process entry
	int Get_Process_Id(AddrSpace*);
	AddrSpace* Get_AddressSpace(int id);
	
private:
	ProcessEntry processEntries[NUMBER_OF_PROCESSES];
	ThreadEntry threadEntries[NUMBER_OF_PROCESSES][NUMBER_OF_THREADS_PER_PROCESS];
	int numberOfActiveProcesses;
	int numberOfThreads[NUMBER_OF_PROCESSES];
	Lock* proccessTableLock;
	int idCounter;
};
#endif
#endif
